// =============================================================================
// FileName : scheduler.v
// Function : This module consists solely of a testbench.
//            It illustrates scheduling differences between blocking and
//            nonblocking statements.
//
// -----------------------------------------------------------------
// Author   : QilinZhao
// Version  : v-1.0
// Date     : 2013-08-28
// E-mail   : forqilin@163.com
// copyright: QiXin Studio
// =================================================================

`timescale 1ns/1ns

module scheduler;

reg clock;
reg[3:0] count    , 
         n3_2_1_0 , // 'n' for no-delay blocking assignment.
         N3_2_1_0 , // 'N' for no-delay Nonblocking.
         z3_2_1_0 , // 'z' for #0 (zero) delayed blocking.
         Z3_2_1_0 , // 'Z' for #0 (zero) delayed Nonblocking.
         D3_2_1_0 , // 'D' for #1 delayed Nonblocking.
         d3_2_1_0 ; // 'd' for #1 delayed blocking.

// clock generator:
always@(clock) #100 clock <= ~clock;

// Stimulus-generating counter:
always@(posedge clock)
begin : Nonblockingcounter  // count will be incremented in the same
  count <= count + 4'h1;    // simulation epoch as posedge clock, but
end                         // only after active events and #0 events.

// -------------------------------------------------------------------------
always@(posedge clock)      // => Not recommended according to Coding Style
begin : NoDelayBlocking     // Uses old count value before
  n3_2_1_0 = count;         // Nonblockingcounter can evaluate
end                         // its rhs or update the count value.

always@(posedge clock)
begin : NoDelayNonBlocking  // Uses old count value, the same one that   
  N3_2_1_0 <= count;        // Nonblockingcounter will update.
end

always@(posedge clock)
begin : ZeroDelayBlocking    // The nonblocking update in
  #0 z3_2_1_0 = count;       // Nonblockingcounter follows all #0
end                          // updates, so the old value is used.

always@(posedge clock)
begin : ZeroDelayNonBlocking // The nonblocking update in
  #0 Z3_2_1_0 <= count;      // Nonblockingcounter follows all #0
end                          // updates, so the old value is used.

always@(posedge clock)
begin : OneDelayNonBlocking  // #1 schedules this evaluation 1 ns in
  #1 D3_2_1_0 <= count;      // the future, after the posedge clock
end                          // epoch, so the new value of count is used.

always@(posedge clock)
begin : OneDelayBlocking     // There is only one (new) count value
  #1 d3_2_1_0 = count;       // available 1 ns after the posedge, so
end                          // blocking and nonblocking evaluations
                             // produce the same result.

// ------------------------------------------------------------------------
// The monitor region evaluations follow all current-epoch active,
// #0, and nonblocking evaluations.   Thus, undelayed $strobe
// sees only the undelayed new value of count:

always@(posedge clock)
begin : MonitorRegion

  // The $display and $strobe task are idential except that $display automatically
  // adds a newline character to the end of its output, whereas the $write task does not.

   $display("time=%04d:  N=%02d n=%02d Z=%02d z=%02d D=%02d d=%02d\n"
  // $write("time=%04d:  N=%02d n=%02d Z=%02d z=%02d D=%02d d=%02d\n"


  // The $strobe task display simualtion data at the selected time.
  // That time ie the end of the current simulation time, when all the simualtion events
  // have occurred for that simulation time, just before simualtion time is advanced.

  // $strobe("time=%04d:  N=%02d n=%02d Z=%02d z=%02d D=%02d d=%02d\n"
  
  // The $monitor task monitors and displays the values of any variables or expressions 
  // specified as argument to the task.
  // $monitor("time=%04d:  N=%02d n=%02d Z=%02d z=%02d D=%02d d=%02d\n"
         , $time, N3_2_1_0, n3_2_1_0, Z3_2_1_0, z3_2_1_0, D3_2_1_0, d3_2_1_0);
end

initial
begin
  clock     = 1'b0; // Before time 0.
  #10 count =  'b0;
  
  #4000 $finish;
 end

initial
begin
  $vcdpluson();
end
endmodule // scheduler
